package SubjectTree.Two;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import Utility.TreeNode;

public class IsSubtree {

/**
 * 难度：简单
 * 
 * 572. 另一个树的子树
 * 	给定两个非空二叉树 s 和 t，检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一
 * 	个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
 * 	
 * 示例 1:
 * 	给定的树 s:
 * 	     3
 * 	    / \
 * 	   4   5
 * 	  / \
 * 	 1   2
 * 	给定的树 t：
 * 	   4 
 * 	  / \
 * 	 1   2
 * 	返回 true，因为 t 与 s 的一个子树拥有相同的结构和节点值。
 * 	
 * 示例 2:
 * 	给定的树 s：
 * 	     3
 * 	    / \
 * 	   4   5
 * 	  / \
 * 	 1   2
 * 	    /
 * 	   0
 * 	给定的树 t：
 * 	   4
 * 	  / \
 * 	 1   2
 * 	返回 false。
 *
 * */
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		IsSubtree is = new IsSubtree();
		System.out.println(is.isSubtree(TreeNode.MkTree("[3,4,5,1,2]"), TreeNode.MkTree("[4,1,2]")));
	}
	//自己写(递归)
	public boolean isSubtree(TreeNode s, TreeNode t) {
        if(s==null)return false;
        return check1(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
    }
	public boolean check1(TreeNode s, TreeNode t) {
		if(s==null&&t==null)return true;
        if(s==null||t==null||s.val!=t.val)return false;
        return check1(s.left, t.left) && check1(s.right, t.right);
	}
	
	//方法一：DFS 暴力匹配
	public boolean isSubtree1(TreeNode s, TreeNode t) {
        return dfs(s, t);
    }
    public boolean dfs(TreeNode s, TreeNode t) {
        if (s == null) {
            return false;
        }
        return check(s, t) || dfs(s.left, t) || dfs(s.right, t);
    }
    public boolean check(TreeNode s, TreeNode t) {
        if (s == null && t == null) {
            return true;
        }
        if (s == null || t == null || s.val != t.val) {
            return false;
        }
        return check(s.left, t.left) && check(s.right, t.right);
    }
    //方法二：DFS 序列上做串匹配
    List<Integer> sOrder = new ArrayList<Integer>();
    List<Integer> tOrder = new ArrayList<Integer>();
    int maxElement, lNull, rNull;
    public boolean isSubtree2(TreeNode s, TreeNode t) {
        maxElement = Integer.MIN_VALUE;
        getMaxElement(s);
        getMaxElement(t);
        lNull = maxElement + 1;
        rNull = maxElement + 2;

        getDfsOrder(s, sOrder);
        getDfsOrder(t, tOrder);

        return kmp();
    }
    public void getMaxElement(TreeNode t) {
        if (t == null) {
            return;
        }
        maxElement = Math.max(maxElement, t.val);
        getMaxElement(t.left);
        getMaxElement(t.right);
    }
    public void getDfsOrder(TreeNode t, List<Integer> tar) {
        if (t == null) {
            return;
        }
        tar.add(t.val);
        if (t.left != null) {
            getDfsOrder(t.left, tar);
        } else {
            tar.add(lNull);
        }
        if (t.right != null) {
            getDfsOrder(t.right, tar);
        } else {
            tar.add(rNull);
        }
    }
    public boolean kmp() {
        int sLen = sOrder.size(), tLen = tOrder.size();
        int[] fail = new int[tOrder.size()];
        Arrays.fill(fail, -1);
        for (int i = 1, j = -1; i < tLen; ++i) {
            while (j != -1 && !(tOrder.get(i).equals(tOrder.get(j + 1)))) {
                j = fail[j];
            }
            if (tOrder.get(i).equals(tOrder.get(j + 1))) {
                ++j;
            }
            fail[i] = j;
        }
        for (int i = 0, j = -1; i < sLen; ++i) {
            while (j != -1 && !(sOrder.get(i).equals(tOrder.get(j + 1)))) {
                j = fail[j];
            }
            if (sOrder.get(i).equals(tOrder.get(j + 1))) {
                ++j;
            }
            if (j == tLen - 1) {
                return true;
            }
        }
        return false;
    }
}
